#ifndef N1TEST_H_2006_07_29
#define N1TEST_H_2006_07_29

#include "N1Lib.h"

const N1Int32 N1TestReturnCodeError               = -1;
const N1Int32 N1TestReturnCodeOK                  = 0;
const N1Int32 N1TestReturnCodeException           = 1;
const N1Int32 N1TestReturnCodeUserDefinedErrorMin = 25;
const N1Int32 N1TestReturnCodeUserDefinedErrorMax = 255;

#define N1TEST_FUNCTION_DEFINITION(name) int name();

#define N1TEST_ADD1(function) \
   N1TEST_FUNCTION_DEFINITION(function) \
   static bool gTest_##function = N1Tests::addTest( #function, function, "N1Lib", NULL, N1_OS_All, 0);

#define N1TEST_ADD2(function, code) \
   N1TEST_FUNCTION_DEFINITION(function) \
   static bool gTest_##function = N1Tests::addTest( #function, function, "N1Lib", NULL, N1_OS_All, code);

#define N1TEST_RUN(function) \
    N1Tests::runTest(#function);


const N1Int32 N1NeedConsole   = 1;
const N1Int32 N1NeedDesktop   = 2;


const N1Int32 N1_OS_All       = 0xffffffff;
const N1Int32 N1_OS_Windows   = 1;

typedef int(*N1TestFunction)();

class NEXPORT N1Test : public N1Object {
protected:
    const char*    m_name;
    const char*    m_description;
    N1UInt32       m_operationSystems;
    N1TestFunction m_testFunction;
    N1Int32        m_returnCode;

    friend class N1Tests;

    N1Test(const char* name, const char* desc, N1UInt32 OSs, 
           N1TestFunction testFunction, N1Int32 retCode) : 
           m_name(name), m_description(desc), m_operationSystems(OSs), 
           m_testFunction(testFunction), m_returnCode(retCode)
    { }

public:
    N1NAME(N1Test)
    N1DESC

    /* Test functions name */
    inline const char*    getName() const {
        return m_name; 
    };

    /* Can be NULL */
    inline const char*    getDescription() const {
        return m_description; 
    };

    /* Set of operation systems under which test must run */
    inline N1UInt32       getOperationSystems() const {
        return m_operationSystems;
    };

    /* Pointer to test function */
    inline N1TestFunction getFunction() const {
        return m_testFunction;
    };

    /* Return expected return code for test */
    inline N1UInt32       getReturnCode() const {
        return m_returnCode;
    };

    /* Runs test: return 0 is success (test returned code m_returnCode)   */
    int runTest() const {
        int ret;
        try 
        {
            ret = m_testFunction();
        }
        catch(...)
        {
            if (N1TestReturnCodeException == m_returnCode)
                return N1TestReturnCodeOK;
        }
        if (ret == m_returnCode)
            return N1TestReturnCodeOK;

        return ret;
    }
};

class N1List;

class NEXPORT N1Tests {
public:
    static bool addTest(const char *name, N1TestFunction function, const char* groups, const char* desc, N1Int32 OSs, N1Int32 retCode);

    static bool runAllTests();
    static int  runTest(const char *test);
};

#endif //N1TEST_H_2006_07_29
